/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.dorian.atomicuml.controllers;

import com.dorian.atomicuml.dao.interfaces.DiagrammsManager;
import com.dorian.atomicuml.dao.interfaces.DiagrammsProjectsManager;
import com.dorian.atomicuml.dao.interfaces.ProjectManager;
import com.dorian.atomicuml.dao.interfaces.UserManager;
import com.dorian.atomicuml.dao.interfaces.UsersProjectManager;
import com.dorian.atomicuml.models.DiagrammInfoData;
import com.dorian.atomicuml.models.EditInfoValidator;
import com.dorian.atomicuml.models.LoginValidator;
import com.dorian.atomicuml.models.ProjectInfoData;
import com.dorian.atomicuml.models.ProjectValidator;
import com.dorian.atomicuml.models.UserInfoData;
import com.dorian.atomicuml.orm.Diagramms;
import com.dorian.atomicuml.orm.DiagrammsProjects;
import com.dorian.atomicuml.orm.Projects;
import com.dorian.atomicuml.orm.Users;
import com.dorian.atomicuml.orm.UsersProjects;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

/**
 *
 * @author cedric.creusot
 * This class is use to control all the web flow of the application
 * with web client.
 */
@Controller
@SessionAttributes({"user"})
public class NavigationController {
    @Autowired
    private ProjectManager projectManager;
    
    @Autowired
    private UsersProjectManager usersprojectManager;
    
    @Autowired
    private DiagrammsManager diagrammsManager;
    
    @Autowired
    private DiagrammsProjectsManager diagrammsProjectsManager;

    @Autowired
    private UserManager userManager;
    
    @Autowired
    private MessageSource messageSource;

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    public void setUserManager(UserManager userManager) {
        this.userManager = userManager;
    }
    
    public void setProjectManager(ProjectManager projectManager) {
        this.projectManager = projectManager;
    }

    public void setUsersprojectManager(UsersProjectManager usersprojectManager) {
        this.usersprojectManager = usersprojectManager;
    }
    
    public void setDiagrammsManager(DiagrammsManager diagrammsManager) {
        this.diagrammsManager = diagrammsManager;
    }

    public void setDiagrammsProjectsManager(DiagrammsProjectsManager diagrammsProjectsManager) {
        this.diagrammsProjectsManager = diagrammsProjectsManager;
    }

    // Initialise le session attribute si celui-ci est a null.
    // Permet d'évité des erreurs si le post c'est mal produit.
    @ModelAttribute("user")
    public UserInfoData generateUserInfo()
    {
        return (new UserInfoData());
    }
    
    @RequestMapping(value="/index.htm", method=RequestMethod.GET)
    public void initView(@ModelAttribute("user") UserInfoData userInfo)
    {
        if (userInfo.isIsLogged())
        {
            System.out.println("YES");
        }
        else
        {
            System.out.println("FALSE");
        }
    }
    
    @RequestMapping(value="/index.htm", params="action=disconnect", method=RequestMethod.GET)
    public String disconnect(@ModelAttribute("user") UserInfoData userInfo, SessionStatus status)
    {
        // Here we clear all session attribute with status.setComplete();
        status.setComplete();
        return "redirect:/index.htm";
    }
    
    
    @RequestMapping(value="/index.htm", params="action=myinfo", method=RequestMethod.GET)
    public ModelAndView initMyInfo(@ModelAttribute("user") UserInfoData userInfo)
    {
        ModelAndView mv = new ModelAndView("index");
        UserInfoData uid = new UserInfoData();
        try
        {
            Users u = this.userManager.getUser(userInfo.getMail());
            uid.setMail(u.getMail());
            uid.setLastname(u.getLastname());
            uid.setFirstname(u.getFirstname());
        }
        catch (Exception ex) {
            Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
        }
        mv.addObject("userInfo", uid);
        return mv;
    }
    
    @RequestMapping(value="/index.htm", params="action=myinfo", method=RequestMethod.POST)
    public ModelAndView submitUpdateMyInfo(@ModelAttribute("userInfo") UserInfoData userInfo,
                                           BindingResult result)
    {
        ModelAndView mv = new ModelAndView("index");
        new EditInfoValidator(this.messageSource).validate(userInfo, result);
        if (!result.hasErrors())
        {
            try
            {
                Users u = this.userManager.getUser(userInfo.getMail());
                u.setFirstname(userInfo.getFirstname());
                u.setLastname(userInfo.getLastname());
                if (userInfo.getPassword() != null && !userInfo.getPassword().isEmpty())
                    u.setPassword(userInfo.getPassword());
                System.out.println("before update");
                this.userManager.updateUser(u);
            }
            catch (Exception ex) {
                Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
            }
                
        }
        return mv;
    }
    
    
    @RequestMapping(value="/index.htm", method=RequestMethod.POST)
    public ModelAndView submitLoginForm(@ModelAttribute("user") UserInfoData userInfo,
                                   BindingResult result,
                                   SessionStatus status)
    {
        ModelAndView mv = new ModelAndView("index");
        new LoginValidator(this.messageSource).validate(userInfo, result);
        if (!result.hasErrors())
        {
            try{
                if (this.userManager.checkLogin(userInfo.getMail(), userInfo.getPassword()))
                {
                    userInfo.setIsLogged(true);
                }
                else
                {
                    String msg = "";
                    String msg2 = "";
                    try
                    {
                        msg = this.messageSource.getMessage("login.errors.password", null, Locale.FRENCH);
                        msg2 = this.messageSource.getMessage("login.errors.login", null, Locale.FRENCH);
                    }
                    catch (Exception e)
                    {
                        System.out.println("Error 2 : " + e);
                    }
                    result.rejectValue("password",
                                   "errors.required",
                                   new Object[] {"password"},
                                   msg);
                    result.rejectValue("mail",
                       "errors.required",
                       new Object[] {"mail"},
                       msg2);
                }
            }
            catch (Exception ex) {
                Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
            }
            // status.sestComplete clear all the session attribute !
            // this is a fucking bad thing ! In your case !
            //status.setComplete();
        }
        return mv;
    }
    
    @RequestMapping(value="/index.htm", params="action=myprojects", method=RequestMethod.GET)
    public ModelAndView initCreateProject(@ModelAttribute("user") UserInfoData user)
    {
        ModelAndView mv = new ModelAndView("index");
        mv.addObject("projectInfo", new ProjectInfoData());
        try {
            Users u = (Users)this.userManager.getUser(user.getMail());
            mv.addObject("userid", u.getId());
            mv.addObject("projectList", this.usersprojectManager.getAllProjectsFromUsersID(u.getId()));
        } catch (Exception ex) {
            Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
        }
        return mv;
    }
    
    @RequestMapping(value="/index.htm", params={"action=myprojects", "proj", "delete"}, method=RequestMethod.GET)
    public ModelAndView deleteProject(@RequestParam("proj") String projId,
                                      @ModelAttribute("user") UserInfoData user)
    {
        try {
            Users u = this.userManager.getUser(user.getMail());
            Projects p = this.projectManager.getProject(Integer.parseInt(projId));
            if (u.getId().intValue() == p.getOwnerId().intValue())
            {
               List<UsersProjects> lup = this.usersprojectManager.getUsersProject(p.getId());
               for (UsersProjects up : lup)
                   this.usersprojectManager.deleteUsersProjects(up);
               List<DiagrammsProjects> ldp = this.diagrammsProjectsManager.getDiagrammsProject(p.getId());
               for (DiagrammsProjects dp : ldp)
               {
                   this.diagrammsManager.deleteDiagramms(dp.getDiagrammsId());
                   this.diagrammsProjectsManager.deleteDiagramms(dp.getProjectsId(), dp.getDiagrammsId());
               }
               this.projectManager.deleteProject(p.getId());
            }
            else
                return new ModelAndView(new RedirectView("./policy.htm"));
        } catch (Exception ex) {
            Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
        }
        return new ModelAndView(new RedirectView("./index.htm?action=myprojects"));
    }

    @RequestMapping(value="/index.htm", params="action=myprojects", method=RequestMethod.POST)
    public ModelAndView submitCreateProjectForm(
                                   @ModelAttribute("user") UserInfoData userInfo,
                                   @ModelAttribute("projectInfo") ProjectInfoData projectInfo,
                                   BindingResult result,
                                   SessionStatus status)
    {
        ModelAndView mv = null;
        new ProjectValidator(this.messageSource).validate(projectInfo, result);
        
        if (!result.hasErrors())
        {
            try{
                Users u = this.userManager.getUser(userInfo.getMail());
                this.projectManager.createProject(projectInfo.getProjectTitle(), projectInfo.getProjectDescription(), u.getId());
                String[] users = projectInfo.getProjectUsers().split(";");
                boolean findUser = false;
                for (String user : users) {
                    if (user.equals(userInfo.getMail()))
                        findUser = true;
                    this.usersprojectManager.addUser(projectInfo.getProjectTitle(), user);
                }
                if (!findUser)
                    this.usersprojectManager.addUser(projectInfo.getProjectTitle(), userInfo.getMail());
                mv = new ModelAndView(new RedirectView("./index.htm?action=myprojects"));
            }
            catch (Exception ex) {
                Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
                result.rejectValue("projectTitle",
                                   "errors.required",
                                   new Object[] {"projectTitle"},
                                   this.messageSource.getMessage("project.errors.exist", null, Locale.FRENCH));
                mv = new ModelAndView("index");
            }
        }
        return mv;
    }

    @RequestMapping(value="/index.htm", params="proj", method=RequestMethod.GET)
    public ModelAndView initProjectView(@RequestParam("proj") String proj,
                                        @ModelAttribute("user") UserInfoData user)
    {
        ModelAndView mv = new ModelAndView("index");
        
        try {
            Users u = this.userManager.getUser(user.getMail());
            mv.addObject("userid", u.getId());
            if (!this.usersprojectManager.isUsersProject(Integer.parseInt(proj), 
                                                    u.getId()))
                return new ModelAndView(new RedirectView("./policy.htm"));
        } catch (Exception ex) {
            Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        mv.addObject("diagrammInfo", new DiagrammInfoData());
        try
        {
            Projects p = this.projectManager.getProject(Integer.parseInt(proj));
            mv.addObject("project", p);
            List<DiagrammsProjects> ldp = this.diagrammsProjectsManager.getDiagrammsProject(Integer.parseInt(proj));
            List<Diagramms> ldi = new ArrayList<Diagramms>();
            for (DiagrammsProjects dp : ldp)
            {
                Diagramms d = this.diagrammsManager.getDiagramms(dp.getDiagrammsId());
                if (d != null)
                ldi.add(d);
            }
            mv.addObject("diagrammList", ldi);
        }
        catch (Exception ex) {
            Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
        }
        return mv;
    }
    
    @RequestMapping(value="/index.htm", params="proj", method=RequestMethod.POST)
    public ModelAndView submitNewDiagramms(@RequestParam("proj") String proj,
                                           @ModelAttribute("user") UserInfoData user,
                                           @ModelAttribute("diagrammInfo") DiagrammInfoData diagInfo,
                                           BindingResult result,
                                           SessionStatus status)
    {
        ModelAndView mv = null;
        if (!result.hasErrors())
        {
           try
           {
               Users u = this.userManager.getUser(user.getMail());
               int diagId = this.diagrammsManager.createDiagramms(diagInfo.getName(), diagInfo.getDescription(), u.getId());
               if (diagId == -1)
                   return null;

               this.diagrammsProjectsManager.addDiagramms(Integer.parseInt(proj), diagId);
               mv = new ModelAndView(new RedirectView("./index.htm?proj="+ proj + "&diag=" + diagId));
           }
           catch (Exception ex) {
            Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
           }
        }
        return mv;
    }
    
    @RequestMapping(value="/index.htm", params={"proj", "diag", "action=delete"}, method = RequestMethod.GET)
    public ModelAndView deleteDiagramms(@RequestParam("proj") String projId,
                                        @RequestParam("diag") String diagId,
                                        @ModelAttribute("user") UserInfoData user)
    {
        try {
            Users u = this.userManager.getUser(user.getMail());
            Projects p = this.projectManager.getProject(Integer.parseInt(projId));
            if (u.getId().intValue() == p.getOwnerId().intValue())
            {
                this.diagrammsManager.deleteDiagramms(Integer.parseInt(diagId));
                this.diagrammsProjectsManager.deleteDiagramms(Integer.parseInt(projId),
                                                              Integer.parseInt(diagId));
            }
            else
                return new ModelAndView(new RedirectView("./policy.htm"));
        } catch (Exception ex) {
            Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
        }
        return new ModelAndView(new RedirectView("./index.htm?proj="+projId));
    }
    
    @RequestMapping(value="/index.htm", params={"proj", "diag"}, method= RequestMethod.GET)
    public ModelAndView initDiagrammEditor(@RequestParam("proj") String projId,
                                           @RequestParam("diag") String diagId,
                                           @ModelAttribute("user") UserInfoData user)
    {
        ModelAndView mv = new ModelAndView("index");
        try {
            Users u = this.userManager.getUser(user.getMail());
            boolean testProjDiag = this.diagrammsProjectsManager.isDiagrammsPartOfTheProject(Integer.parseInt(projId), Integer.parseInt(diagId));
            boolean testProjUser = this.usersprojectManager.isUsersProject(Integer.parseInt(projId), u.getId());
            if (!testProjUser ||
                !testProjDiag)
                return new ModelAndView(new RedirectView("./policy.htm"));
            DiagrammInfoData did = new DiagrammInfoData();
            Diagramms d = this.diagrammsManager.getDiagramms(Integer.parseInt(diagId));
            did.setData(d.getData());
            did.setEditor(this.userManager.getUser(d.getEditorId()).getMail());
            did.setName(d.getName());
            did.setHeight(d.getHeight().toString());
            did.setWidth(d.getWidth().toString());
            mv.addObject("diagramm", did);
            List<UsersProjects> lup = this.usersprojectManager.getUsersProject(Integer.parseInt(projId));
            List<String> usersList = new ArrayList();
            for (UsersProjects up : lup) {
                String mail = this.userManager.getUser(up.getUsersId()).getMail();
                if (mail != null && mail.length() > 0)
                    usersList.add(mail);
            }
            mv.addObject("usersList", usersList);
            mv.addObject("userid", u.getId());
            mv.addObject("project", this.projectManager.getProject(Integer.parseInt(projId)));
        } catch (Exception ex) {
            Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
        }
        return mv;
    }
    
    @RequestMapping(value="/index.htm", params={"proj", "diag"}, method= RequestMethod.POST)
    public ModelAndView submitChange(@RequestParam("proj") String projId,
                                     @RequestParam("diag") String diagId,
                                     @ModelAttribute("diagramm") DiagrammInfoData diag,
                                     BindingResult result,
                                     SessionStatus status)
    {
        try {
            Diagramms d = this.diagrammsManager.getDiagramms(Integer.parseInt(diagId));
            Users u = null;
            if (diag.getEditor() != null)
                 u = this.userManager.getUser(diag.getEditor());
            if ((d.getData() == null && diag.getData() != null && diag.getData().length() > 0) || 
                (d.getData() != null && diag.getData() != null && diag.getData().length() > 0 && !d.getData().equals(diag.getData())))
                d.setData(diag.getData());
            if (u != null && u.getId().intValue() != d.getEditorId().intValue())
                d.setEditorId(u.getId());
            if (diag.getHeight() != null &&
                diag.getHeight().length() > 0 &&
                !d.getHeight().toString().equals(diag.getHeight()))
                d.setHeight(Integer.parseInt(diag.getHeight()));
            if (diag.getWidth() != null &&
                diag.getWidth().length() > 0 &&
                !d.getWidth().toString().equals(diag.getWidth()))
                d.setWidth(Integer.parseInt(diag.getWidth()));
            if (this.diagrammsManager.updateDiagramms(d))
                Logger.getLogger(NavigationController.class.getName()).log(Level.INFO, null, "Update diagram");
        } catch (Exception ex) {
            Logger.getLogger(NavigationController.class.getName()).log(Level.SEVERE, null, ex);
        }
        return new ModelAndView(new RedirectView("./index.htm?proj="+ projId + "&diag=" + diagId));
    }
}
